package com.gkj.shiro.credentialsMatcher;

import com.alibaba.fastjson.JSONObject;
import com.gkj.blog.business.consts.SessionConst;
import com.gkj.blog.business.service.UserService;
import com.gkj.blog.business.vo.entity.User;
import com.gkj.blog.framework.holder.RequestHolder;
import com.gkj.blog.util.IpUtil;
import com.gkj.blog.util.RedisUtil;
import com.gkj.blog.util.SessionUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Component
public class RetryLimitCredentialsMatcher extends RSACredentialsMatcher {

    private static final Logger LOGGER = LoggerFactory.getLogger(RetryLimitCredentialsMatcher.class);
    /**
     * 用户登录次数计数  redisKey 前缀
     */
    private static final String SHIRO_LOGIN_COUNT = "shiro_login_count_";
    /**
     * 用户登录是否被锁定 redisKey 前缀
     */
    private static final String SHIRO_IS_LOCK = "shiro_is_lock_";
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    private UserService userService;
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        User user = (User) info.getPrincipals().getPrimaryPrincipal();
        String username = user.getUsername();
        LOGGER.info("== 验证用户：{}",username);
        // 访问一次，计数一次
        String ip=IpUtil.getRealIp(RequestHolder.getRequest());
        String loginCountKey = SHIRO_LOGIN_COUNT + ip;
        String isLockKey = SHIRO_IS_LOCK + ip;
        if(redisUtil.exists(loginCountKey)){
            redisUtil.set(loginCountKey,(Integer)redisUtil.get(loginCountKey)+1);
        }else{
            redisUtil.set(loginCountKey,1);
        }

        if (redisUtil.exists(isLockKey)) {
            throw new ExcessiveAttemptsException("请在"+redisUtil.getExpire(isLockKey,TimeUnit.MINUTES)+"分钟后尝试登录！");
        }

        // 计数大于5时，登录被锁定

        Integer loginCount = (Integer) redisUtil.get(loginCountKey);
        int retryCount = 5 -loginCount;
        if (retryCount < 0) {
            redisUtil.set(isLockKey, "LOCK",600L);//10分钟锁定时间
            redisUtil.expire(loginCountKey,5L,TimeUnit.MINUTES);
            throw new ExcessiveAttemptsException("由于密码输入错误次数过多，你在10分钟内被禁止使用登录操作！");
        }

        boolean matches = super.doCredentialsMatch(token, info);
        if (!matches) {
            throw new AccountException("帐号或密码不正确！您还剩" + retryCount + "次重试的机会");
        }

        //清空登录计数
        redisUtil.remove(loginCountKey);
        userService.updateUserLastLoginInfo(user);
        SessionUtil.setUser(user);
        return matches;
    }
}
